package com.test.aop;

import net.sf.cglib.proxy.MethodInterceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
 * JDK动态代理实现类，用于创建代理对象并拦截方法调用
 */
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {

    private final AdvisedSupport advised;

    /**
     * 构造方法，初始化AdvisedSupport对象
     *
     * @param advised 代理配置支持对象
     */
    public JdkDynamicAopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }

    /**
     * 获取代理对象
     *
     * @return 代理对象
     */
    @Override
    public Object getProxy() {
        return getProxy(Thread.currentThread().getContextClassLoader());
    }

    /**
     * 使用指定的类加载器获取代理对象
     *
     * @param classLoader 类加载器
     * @return 代理对象
     * @throws IllegalStateException 如果目标类没有实现接口
     */
    @Override
    public Object getProxy(ClassLoader classLoader) {
        if (this.advised.getTargetSource() == null){
            throw new IllegalStateException("TargetSource不能为空");
        }
        Class<?> targetClass = advised.getTargetSource().getTargetClass();
        Class<?>[] interfaces = targetClass.getInterfaces();
        if (interfaces.length == 0){
            throw new IllegalStateException("目标类必须实现接口");
        }
        return Proxy.newProxyInstance(classLoader, interfaces, this);
    }

    /**
     * 拦截方法调用
     *
     * @param proxy 代理对象
     * @param method 被调用的方法
     * @param args 方法参数
     * @return 方法返回值
     * @throws Throwable 方法调用过程中抛出的异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object target = null;

        try{
            target = advised.getTargetSource().getTarget();
            if (target == null){
                throw  new IllegalStateException("目标对象不能为空");
            }
            Method tartgetMethod = null;
            try{
                tartgetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());
            }catch (NoSuchMethodException e){
                tartgetMethod = method;
            }

            List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice(tartgetMethod, target.getClass());

            if (chain.isEmpty()){
                return method.invoke(target, args);
            }

            ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(target, tartgetMethod, args);
            return processInterceptors(chain, invocation);
        }finally {
            if (target != null){
                advised.getTargetSource().releaseTarget(target);
            }
        }
    }

    /**
     * 处理拦截器链
     *
     * @param chain 拦截器链
     * @param invocation 方法调用信息
     * @return 方法返回值
     * @throws Throwable 方法调用过程中抛出的异常
     */
    private Object processInterceptors(List<Object> chain, ReflectiveMethodInvocation invocation) throws Throwable {
        AopMethodInvocation methodInvocation = new AopMethodInvocation(invocation, chain);
        return methodInvocation.proceed();
    }

    /**
     * AopMethodInvocation类，用于处理拦截器链的调用
     */
    private static class AopMethodInvocation extends ReflectiveMethodInvocation {
        private final List<Object> interceptorsAndAdvices;
        private int currentInterceptorIndex = -1;

        /**
         * 构造方法，初始化拦截器链和调用信息
         *
         * @param invocation 方法调用信息
         * @param interceptorsAndAdvices 拦截器链
         */
        public AopMethodInvocation(ReflectiveMethodInvocation invocation, List<Object> interceptorsAndAdvices) {
            super(invocation.getThis(), invocation.getMethod(), invocation.getArguments());
            this.interceptorsAndAdvices = interceptorsAndAdvices;
        }

        @Override
        public Method getMethod() {
            return null;
        }

        @Override
        public Object[] getArguments() {
            return new Object[0];
        }

        @Override
        public Object getThis() {
            return null;
        }

        /**
         * 执行拦截器链中的下一个拦截器或目标方法
         *
         * @return 方法返回值
         * @throws Throwable 方法调用过程中抛出的异常
         */
        @Override
        public Object proceed() throws Throwable {
            if (this.currentInterceptorIndex == this.interceptorsAndAdvices.size() - 1){
                return super.proceed();
            }

            Object interceptorOrAdvice = this.interceptorsAndAdvices.get(++this.currentInterceptorIndex);

            if (interceptorOrAdvice instanceof MethodInterceptor){
                MethodBeforeAdvice beforeAdvice = (MethodBeforeAdvice) interceptorOrAdvice;
                beforeAdvice.before(getMethod(), getArguments(), getThis());
                return proceed();
            }else if (interceptorOrAdvice instanceof AfterReturningAdvice){
                Object returnValue = proceed();
                AfterReturningAdvice afterAdvice = (AfterReturningAdvice) interceptorOrAdvice;
                afterAdvice.afterReturning(returnValue, getMethod(), getArguments(), getThis());
                return returnValue;
            }else {
                throw  new IllegalStateException("未知的拦截器类型: " + interceptorOrAdvice);
            }
        }
    }
}
